package com.cefa.edu.util;

import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Maps;

/**
 * 签名工具类
 * @author huiwu
 *
 */
public final class SignUtil {

    private static final Logger logger = LoggerFactory.getLogger(SignUtil.class);
    /**
     * 默认的签名密钥
     */
    private static final String DEFAULT_SECRET = "#a@!bcd<>ef@%^_g+-=*(7aweqweqwkjl$32123";

    /**
     * 默认的签名参数名称
     */
    private static final String SIGN_PARAM_NAME = "sign";

    private static final SignMethod SIGN_METHOD = SignMethod.MD5;

    public enum SignMethod{
        MD5,SHA1
    }

    private String signName = null;

    private SignMethod signMethod = null;

    private SignUtil(){
        this(SIGN_PARAM_NAME,SIGN_METHOD);
    }

    private SignUtil(String signName,SignMethod signMethod){
        this.signName = signName;
        this.signMethod = signMethod;
    }


    public static SignUtil build(){
        return new SignUtil();
    }

    public static SignUtil build(String signName){
        if (StringUtils.isBlank(signName)) {
            throw new NullPointerException("Sign param name is null");
        }
        return new SignUtil(signName,SIGN_METHOD);
    }

    public static SignUtil build(SignMethod signMethod){
        if (signMethod==null) {
            throw new NullPointerException("Sign param name is null");
        }
        return new SignUtil(SIGN_PARAM_NAME,signMethod);
    }

    public static SignUtil build(String signName,SignMethod signMethod){
        if (StringUtils.isBlank(signName)||signMethod==null) {
            throw new NullPointerException("Sign param name is null");
        }
        if (signMethod!=SignMethod.MD5&&signMethod!=SignMethod.SHA1) {
            throw new IllegalArgumentException("Not support sign method "+signMethod);
        }
        return new SignUtil(signName,signMethod);
    }

    /**
     * 使用默认的secret对data签名
     * @param data
     * @return
     */
    public  String sign(Map<String,String> data){

        return sign(data, DEFAULT_SECRET);
    }

    /**
     * 对data使用signKey进行签名
     * @param data
     * @param signSecret
     * @return
     */
    public  String sign(Map<String,String> data,String signSecret){

        String req = mapToUrlParam(data, signSecret);
        logger.info("验签字符串是:{}", req);
        if (signMethod==SignMethod.MD5) {
            return DigestUtils.md5Hex(req).toUpperCase();
        }else{
            return DigestUtils.sha1Hex(req).toUpperCase();
        }
    }


    /**
     * 使用默认的KEY签名
     * @param data 格式如a=1&b=2&c=3
     * @return
     */
    public  String sign(String data){
        if (StringUtils.isBlank(data)) {
            return null;
        }
        return sign(data,DEFAULT_SECRET);
    }

    /**
     *
     * @param data 格式如a=1&b=2&c=3
     * @param signSecret 签名key
     * @return
     */
    public  String sign(String data,String signSecret){
        if (StringUtils.isBlank(data)) {
            return null;
        }
        Map<String,String> params = urlParamToMap(data);
        return sign(params, signSecret);
    }


    public  boolean validate(String data,String signSecret){
        if (StringUtils.isBlank(data)||StringUtils.isBlank(signSecret)) {
            return false;
        }
        Map<String,String> params = urlParamToMap(data);
        return validate(params, signSecret);
    }

    public  boolean validate(String data){
        return validate(data, DEFAULT_SECRET);
    }

    /**
     * 验证签名是否正确，data中必须有签名参数
     * @param data
     * @return
     */
    public  boolean validate(Map<String,String> data){
        return validate(data, DEFAULT_SECRET);
    }

    /**
     * 验证签名是否正确，data中必须有签名参数
     * @param data
     * @param signSecret
     * @return
     */
    public  boolean validate(Map<String,String> data,String signSecret){
        if (data==null||data.isEmpty()||!data.containsKey(signName)) {
            return false;
        }
        String sign = data.get(signName);
        data.remove(signName);
        return sign.equals(sign(data, signSecret));
    }

    private static String mapToUrlParam(Map<String, String> data, String signSecret) {
        String str = Joiner.on("#").withKeyValueSeparator("=").join(data);
      //  List<String> list = Lists.newArrayList(Splitter.on("#").trimResults().splitToList(str));
        List<String> list = Lists.newArrayList(Splitter.on("#").splitToList(str));
        Collections.sort(list);
        String req = Joiner.on("&").join(list).concat(signSecret);
        return req;
    }

    private static Map<String,String> urlParamToMap(String data){
        if (StringUtils.isBlank(data)) {
            return null;
        }
        Map<String,String> params = Splitter.on("&").omitEmptyStrings().withKeyValueSeparator("=").split(data);
        Map<String,String> m = Maps.newHashMap();
//        if (params!=null&&!params.isEmpty()){
//            params.forEach((k,v)-> {if (StringUtils.isNotBlank(v)) {
//                m.put(k,v);
//            }});
//        }
            params.forEach((k,v)-> {
                m.put(k,v);
            });
        return m;
    }

    public static void main(String[] args) {
        String url = "app_id=miaomore&timestamp=1508404516&uuid=123456";
        String v = SignUtil.build(SignMethod.MD5).sign(url, "7c0d930c$kDL39#lOJ29dM1");
        System.out.println(v);
        System.out.println(urlParamToMap(url));
    }


}